<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>播放页</title>
  </head>
  <body>
    <video id="video" autoplay></video>

    <span>主播名</span>
    <input id="zhubo" type="text" />
    <button onclick="connect()">建立视频连接</button>

    <button id="start_record">开始录制</button>
    <button id="pause_record">暂停录制</button>
    <button id="resume_record">继续录制</button>
    <button id="stop_record">结束录制</button>
    <button>开始录制</button>
  </body>

  <script type="text/javascript">
    var supported = false;

    var constraints = { audio: true, video: true };
    var chunks = [];

    if (navigator.mediaDevices) {
      console.log("getUserMedia supported.");

      supported = true;
    }

    /**
     * socket.send 数据描述
     * event: 指令类型
     * data: 数据
     * name: 发送人
     * receiver: 接收人
     *
     * */

    //使用Google的stun服务器
    const iceServer = {
      iceServers: [
        {
          url: "stun:stun.l.google.com:19302",
        },
        {
          url: "turn:numb.viagenie.ca",
          username: "webrtc@live.com",
          credential: "muazkh",
        },
      ],
    };

    // 老的浏览器可能根本没有实现 mediaDevices，所以我们可以先设置一个空的对象
    if (navigator.mediaDevices === undefined) {
      navigator.mediaDevices = {};
    }
    // 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
    // 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
    if (navigator.mediaDevices.getUserMedia === undefined) {
      navigator.mediaDevices.getUserMedia = function (constraints) {
        // 首先，如果有getUserMedia的话，就获得它
        var getUserMedia =
          navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

        // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
        if (!getUserMedia) {
          return Promise.reject(
            new Error("getUserMedia is not implemented in this browser")
          );
        }

        // 否则，为老的navigator.getUserMedia方法包裹一个Promise
        return new Promise(function (resolve, reject) {
          getUserMedia.call(navigator, constraints, resolve, reject);
        });
      };
    }

    //兼容浏览器的getUserMedia写法
    const getUserMedia =
      navigator.mediaDevices.getUserMedia ||
      navigator.mediaDevices.mozGetUserMedia ||
      navigator.mediaDevices.webkitGetUserMedia ||
      navigator.mediaDevices.msGetUserMedia;
    //兼容浏览器的PeerConnection写法
    const PeerConnection =
      window.PeerConnection ||
      window.webkitPeerConnection00 ||
      window.webkitRTCPeerConnection ||
      window.RTCPeerConnection ||
      window.mozRTCPeerConnection;

    /**
     * 信令websocket
     * @type {WebSocket}
     */
    var socket;

    /**
     * 视频信息
     * */
    var stream_two;

    /**
     * 播放视频video组件
     * */
    const video = document.getElementById("video");

    const start_record = document.getElementById("start_record");
    const stop_record = document.getElementById("stop_record");
    const pause_record = document.getElementById("pause_record");
    const resume_record = document.getElementById("resume_record");

    /**
     * 连接的浏览器PeerConnection对象组
     * {
     *  'id':PeerConnection
     * }
     * @type {{}}
     */
    var pc = {};

    // 建立scoket连接
    function connect() {
      if (!supported) {
        alert("不支持");
        return false;
      }
      // 获取主播名称
      const zhubo = document.getElementById("zhubo").value;

      if (!zhubo) {
        alert("请输入主播名");
        return;
      }
      localStorage.setItem("anchor", zhubo);
      /**
       * 信令websocket
       * @type {WebSocket}
       */
      socket = new WebSocket("ws://localhost:6533/websocket?name=" + zhubo);

      //获取本地的媒体流，并绑定到一个video标签上输出，并且发送这个媒体流给其他客户端
      getUserMedia(constraints)
        .then(function (stream) {
          //发送offer和answer的函数，发送本地session描述
          stream_two = stream;
          // 旧的浏览器可能没有srcObject
          if ("srcObject" in video) {
            video.srcObject = stream;
          } else {
            // 防止在新的浏览器里使用它，应为它已经不再支持了
            video.src = window.URL.createObjectURL(stream);
          }
          video.onloadedmetadata = function (e) {
            video.play();
          };
          //向PeerConnection中加入需要发送的流

          //如果是发送方则发送一个offer信令，否则发送一个answer信令

          // 录制
          var options = {
            audioBitsPerSecond: 128000,
            videoBitsPerSecond: 2500000,
            mimeType: "video/mp4",
          };
          var mediaRecorder = new MediaRecorder(stream, options);

          // visualize(stream);

          start_record.onclick = function () {
            mediaRecorder.start();
            console.log(mediaRecorder.state);
            console.log("recorder started");
            record.style.background = "red";
            record.style.color = "black";
          };

          stop_record.onclick = function () {
            mediaRecorder.stop();
            console.log(mediaRecorder.state);
            console.log("recorder stopped");
            record.style.background = "";
            record.style.color = "";
          };

          mediaRecorder.onstop = function (e) {
            console.log("data available after MediaRecorder.stop() called.");

            var clipName = prompt("Enter a name for your sound clip");

            var clipContainer = document.createElement("article");
            var clipLabel = document.createElement("p");
            var audio = document.createElement("audio");
            var deleteButton = document.createElement("button");

            clipContainer.classList.add("clip");
            audio.setAttribute("controls", "");
            deleteButton.innerHTML = "Delete";
            clipLabel.innerHTML = clipName;

            clipContainer.appendChild(audio);
            clipContainer.appendChild(clipLabel);
            clipContainer.appendChild(deleteButton);
            soundClips.appendChild(clipContainer);

            audio.controls = true;
            var blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });
            chunks = [];
            var audioURL = URL.createObjectURL(blob);
            audio.src = audioURL;
            console.log("recorder stopped");

            deleteButton.onclick = function (e) {
              evtTgt = e.target;
              evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
            };
          };

          //
          mediaRecorder.ondataavailable = function (e) {
            chunks.push(e.data);
          };
        })
        .catch(function (error) {
          console.log("The following error occurred: " + error);

          //处理媒体流创建失败错误
          alert("处理媒体流创建失败错误");
        });

      socket.close = function () {
        console.log("连接关闭");
      };

      //有浏览器建立视频连接
      socket.onmessage = function (event) {
        var json = JSON.parse(event.data);
        if (json.name && json.name != null && !json.event) {
          pc[json.name] = new PeerConnection(iceServer);
          pc[json.name].addStream(stream_two);
          // 浏览器兼容
          var agent = navigator.userAgent.toLowerCase();
          if (agent.indexOf("firefox") > 0) {
            pc[json.name].createOffer().then(function (desc) {
              pc[json.name].setLocalDescription(desc);
              socket.send(
                JSON.stringify({
                  event: "__offer",
                  data: {
                    sdp: desc,
                  },
                  name: zhubo,
                  receiver: json.name,
                })
              );
            });
          } else if (agent.indexOf("chrome") > 0) {
            pc[json.name].createOffer(
              function (desc) {
                pc[json.name].setLocalDescription(desc);
                socket.send(
                  JSON.stringify({
                    event: "__offer",
                    data: {
                      sdp: desc,
                    },
                    name: zhubo,
                    receiver: json.name,
                  })
                );
              },
              (error) => {
                alert(error);
              }
            );
          } else {
            pc[json.name].createOffer(
              function (desc) {
                pc[json.name].setLocalDescription(desc);
                socket.send(
                  JSON.stringify({
                    event: "__offer",
                    data: {
                      sdp: desc,
                    },
                    name: zhubo,
                    receiver: json.name,
                  })
                );
              },
              (error) => {
                alert(error);
              }
            );
          }
        } else {
          if (json.event === "__ice_candidate") {
            //如果是一个ICE的候选，则将其加入到PeerConnection中
            pc[json.name].addIceCandidate(
              new RTCIceCandidate(json.data.candidate)
            );
          } else if (json.event === "__answer") {
            // 将远程session描述添加到PeerConnection中
            pc[json.name].setRemoteDescription(
              new RTCSessionDescription(json.data.sdp)
            );
          }
        }
      };
    }

    window.onload = function () {
      const anchor = localStorage.getItem("anchor");
      if (anchor) {
        document.getElementById("zhubo").value = anchor;
        connect();
      }
    };

    function checkTypeSuppert() {
      var types = [
        "video/webm",
        "audio/webm",
        "video/webm\;codecs=vp8",
        "video/webm\;codecs=daala",
        "video/webm\;codecs=h264",
        "audio/webm\;codecs=opus",
        "video/mpeg",
      ];

      for (var i in types) {
        console.log(
          "Is " +
            types[i] +
            " supported? " +
            (MediaRecorder.isTypeSupported(types[i]) ? "Maybe!" : "Nope :(")
        );
      }
    }
  </script>
</html>
